package com.cooldatasoft.taskManager;

import java.util.HashMap;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Configurable;

import com.cooldatasoft.security.TaskManagerSecurityManager;
import com.github.wolfie.refresher.Refresher;
import com.vaadin.Application;
import com.vaadin.terminal.ExternalResource;
import com.vaadin.terminal.gwt.server.HttpServletRequestListener;
import com.vaadin.ui.ComponentContainer;
import com.vaadin.ui.LoginForm.LoginEvent;
import com.vaadin.ui.LoginForm.LoginListener;
import com.vaadin.ui.Window;
import com.vaadin.ui.Window.Notification;
import com.cooldatasoft.domain.model.*;
import com.cooldatasoft.exception.TaskManagerException;
import com.cooldatasoft.exception.TaskManagerUserException;

@Configurable(preConstruction = true)
public class TaskManagerApplication extends Application implements LoginListener,
		HttpServletRequestListener {

	private static final long serialVersionUID = 6908438351505423927L;
	private static final Logger logger = Logger.getLogger(TaskManagerApplication.class);

	protected static final String URL_LOGIN_NAME = "login";
	protected static final String URL_PROGRAMMER_NAME = "auth-user";
	protected static final String URL_SUPERVISOR_NAME = "auth-supervisor";
	protected static final String URL_ADMIN_NAME = "auth-admin";
	protected static final long REFRESHER_INTERVAL = 5000l;

	private HttpServletRequest request = null;
	private HttpServletResponse response = null;

	private Window mainWindow;
	private Refresher refresher;

	private Map<String, String> registeredUrls = new HashMap<String, String>();

	@Autowired
	private TaskManagerSecurityManager securityManager;

	private static ThreadLocal<TaskManagerApplication> threadLocal = new ThreadLocal<TaskManagerApplication>(); 
																									

	@Override
	public void init() {
		setInstance(this); 
		setTheme("centrumprosperitytheme");

		mainWindow = new Window("SimpleTaskManager");
		setMainWindow(mainWindow);

		registeredUrls.put(URL_PROGRAMMER_NAME, MainPage.class.getName());

		openWindow();
		refresher = new Refresher();
		refresher.setRefreshInterval(REFRESHER_INTERVAL);
	}

	// @return the current application instance
	public static TaskManagerApplication getInstance() {
		return threadLocal.get();
	}

	// Set the current application instance
	public static void setInstance(TaskManagerApplication application) {
		threadLocal.set(application);
	}

	private void openWindow() {
		if (getCurrentUser() != null) {
			mainWindow.open(new ExternalResource(this.getURL()
					+ URL_PROGRAMMER_NAME));
		} else {
			mainWindow.open(new ExternalResource(this.getURL() + URL_LOGIN_NAME));
		}
	}

	/**
	 * 'hacky' static method, that is called by Vaadin in case when Application
	 * subclass provides it -> java does not allow static method overriding
	 * 
	 * 
	 * @see TaskManagerApplication.getSystemMessages javadoc
	 * 
	 */
	public static SystemMessages getSystemMessages() {
		CustomizedSystemMessages csm = new CustomizedSystemMessages();
		csm.setSessionExpiredMessage("Platnosť Vášho prihlásenia vypršala. Kliknite sem k opätovnému prihláseniu.");
		csm.setSessionExpiredCaption("Platnosť vyhlásenia vypršala");
		
		return csm;
	}

	protected User getCurrentUser() {
		return securityManager.getCurrentUser();
	}

	@Override
	public void onLogin(LoginEvent event) {
		final String username = event.getLoginParameter("username");
		final String password = event.getLoginParameter("password");
		try {
			boolean loginResult = securityManager.login(username, password);
			logger.debug("loginResult: " + loginResult);
			User currentUser = securityManager.getCurrentUser();
			openWindow();
		} catch (TaskManagerException e) {
			logger.info("Could not authenticate user '" + username + "'");
			String mess = "";
			if (e instanceof TaskManagerUserException) {
				TaskManagerUserException ue = ((TaskManagerUserException) e);
				logger.debug("ue.getDictionaryKey(): " + ue.getDictionaryKey()
						+ " ue.getPropertyKeys() : " + ue.getPropertyKeys()
						+ " ue.getDefaultMessage(): " + ue.getDefaultMessage());
				mess = ue.getDefaultMessage(); 
			} else {
				if (!e.isLogged()) {
					logger.error(e.getMessage(), e);
				}
				mess = "Unexpected exception"; 
			}
			
			Window.Notification notification = new Window.Notification("Chyba",
					mess, Notification.TYPE_ERROR_MESSAGE);
			notification.setPosition(Notification.POSITION_CENTERED_TOP);
			notification.setDelayMsec(2000);
			getWindow(URL_LOGIN_NAME).showNotification(notification);
		}
	}

	/**
	 * dynamicky vytvaranie okien podla potreby
	 * 
	 */
	@Override
	public Window getWindow(String name) {

		//logger.info("getWindow: " + name);

		Window w = super.getWindow(name);
		if (w == null) {
			Window newWindow = new Window("Simple task manager");
			newWindow.setName(name);
			if (registeredUrls.containsKey(name)) {
				try {
					newWindow.setContent((ComponentContainer) Class.forName(
							registeredUrls.get(name)).newInstance());
				} catch (InstantiationException e) {
					logger.error("chyba pri inicializovani obsahu", e);
				} catch (IllegalAccessException e) {
					logger.error("chyba pri inicializovani obsahu", e);
				} catch (ClassNotFoundException e) {
					logger.error("chyba pri inicializovani obsahu", e);
				}
			} else {
				if (getCurrentUser() != null) {
					return getWindow(URL_PROGRAMMER_NAME);
				} else {
					name = URL_LOGIN_NAME;
				}
			}

			if (URL_LOGIN_NAME.equals(name)) {
				LoginWindow lWindow = new LoginWindow();
				lWindow.addLoginFormListener(this);
				newWindow.setContent(lWindow);
			} 
			addWindow(newWindow);
			mainWindow = newWindow;
			return newWindow;
		}

		return w;
	}

	/**
	 * This method now provides the local instance of mainWindow which is only
	 * one that is displayed to user (because of our custom window management
	 * logic).
	 * 
	 * Instance obtained throught this getter allows convenient notification
	 * invocation through getApplication.getMainWindow().showNotification(xyz)
	 * method from components. Otherwise, the notification would be popped out
	 * of sight of user (in "hidden" windows).
	 * 
	 * 
	 */
	@Override
	public Window getMainWindow() {
		return mainWindow;
	}

	@Override
	public void close() {
		if (request != null && response != null) {
			securityManager.logout(request, response);
		}

		super.close();
	}

	@Override
	public void onRequestStart(HttpServletRequest request,
			HttpServletResponse response) {
		this.request = request;
		this.response = response;
		TaskManagerApplication.setInstance(this);
	}

	@Override
	public void onRequestEnd(HttpServletRequest request,
			HttpServletResponse response) {
		threadLocal.remove();
	}

	public Refresher getRefresher() {
		return refresher;
	}

	public void setRefresher(Refresher refresher) {
		this.refresher = refresher;
	}
}
